/** template<class T>
 *  bool Node<T> :: isTerminal()
 *
 * This function determines if the node is terminal.
 *
 * @return
 * bool - are child nodes are unaccessible
 *
 */
template<class T>
bool Node<T> :: isTerminal()
{
    if ( !ok () )
        return false;
    if ( left_ || right_ )
       return false; 
    return true;
}

/** template<class T>
 *  bool Node<T> :: isRoot ()
 *
 * This function determines if the node is root node
 *
 * @return
 * bool - is parent is inaccessible
 *
 */
template<class T>
bool Node<T> :: isRoot ()
{
    if ( !ok () )
        return false;
    if ( parent_ )
        return false;
    return true;
}

/** template<class T>
 *  Node* Node<T> :: getLeftChild();
 *
 * This function return left hand side child.
 *
 * @return
 * Node* - left hand side child
 *
 */
template<class T>
Node<T>* Node<T> :: getLeftChild()
{
    if ( !left_ )
        return nullptr;
    if ( !left_->ok () )
        left_ = nullptr;
    return left_;
}


/** template<class T>
 *  Node* Node<T> :: getRightChild();
 *
 * This function return rifht hand side child.
 *
 * @return
 * Node* - right hand side child
 *
 */
template<class T>
Node<T>* Node<T> :: getRightChild()
{
    if ( !right_ )
        return nullptr;
    if ( !right_->ok () )
        right_ = nullptr;
    return right_;
}

/** template<class T>
 *  Node* Node<T> :: getRoot   ();
 *
 * this function return the root of the tree that this node belongs
 *
 * @return
 * Node* - root of this node's tree
 *
 */
template<class T>
Node<T>* Node<T> :: getRoot   ()
{
    if ( !ok () )
        return nullptr;
    if ( parent_ )
        return parent_->getRoot ();
    return this;
}

/** template<class T>
 *  Node* Node<T> :: getParent ();
 *
 * THis function return node's parent
 *
 * @return
 * Node* - parent of this node
 *
 */
template<class T>
Node<T>* Node<T> :: getParent ()
{
    if ( !ok () )
        return nullptr;
    return parent_;
}

/** template<class T>
 *  bool Node<T> :: ok ()
 *
 * this function checks if node is ok
 *
 * @return
 * bool - is ok
 */
template<class T>
bool Node<T> :: ok ()
{
    if ( !this )
        return false;
    if ( destroyed_ )
        return false;
    if ( left_ == parent_  && parent_ )
       return false; 
    if ( left_ == right_   && left_ )
        return false;
    if ( right_ == parent_ && right_ )
        return false;
    return true;
}

/** template<class T>
 *  bool Node<T> :: attatchToLeft  (Node* attachment)
 *
 * This function attaches node to the left hand child. Notice that if 
 * parent node already has left hand side child node it will be overriden.
 * In other words if there is left hand side child it must be saved with
 * getNode function before attaching new one.
 *
 * @param Node* attachment - node to attach
 *
 * @return
 * bool - was attachment done
 *
 */
template<class T>
bool Node<T> :: attatchToLeft  (Node* attachment)
{
    if ( !ok () )
        return false;

    if ( attachment )
    {
        if ( ! attachment->ok() )
            return false;
        if ( attachment == right_ )
            return false;
        if ( attachment == parent_ )
            return false;

        attachment->parent_ = this;
    }

    if ( left_ )
    {
        left_->parent_ = nullptr;
    }

    left_ = attachment;

    return true;
}

/** template<class T>
 *  bool Node<T> :: attatchToRight  (Node* attachment)
 *
 * This function attaches node to the right hand child. Notice that if 
 * parent node already has right hand side child node it will be overriden.
 * In other words if there is right hand side child it must be saved by
 * getRightChild function before attaching new one.
 *
 * @param Node* attachment - node to attach
 *
 * @return
 * bool - was attachment done
 *
 */
template<class T>
bool Node<T> :: attatchToRight  (Node* attachment)
{
    if ( !ok () )
        return false;

    if ( attachment )
    {
        if ( ! attachment->ok() )
            return false;
        if ( attachment == left_ )
            return false;
        if ( attachment == parent_ )
            return false;

        attachment->parent_ = this;
    }

    if ( right_ )
    {
        right_->parent_ = nullptr;
    }

    right_ = attachment;
    return true;
}

/** template<class T>
 *  T* Node<T> :: getValue ()
 *
 * This function returns value stored in the node
 *
 * @return
 * T - template object that was stored in this node
 *
 */
template<class T>
T* Node<T> :: getValue ()
{
    if ( !ok () )
        return nullptr;
    return &value_;
}

/** template<class T>
 *  Node<T> :: Node ();
 *
 * This constructor constructs the root node with no child nodes and
 * value constructed with default constructor
 *
 */
template<class T>
Node<T> :: Node ()
    :
    destroyed_ (false),
    left_      (nullptr),
    right_     (nullptr), 
    parent_    (nullptr),
    value_     ()
{
}

/** template<class T>
 *  Node<T> :: Node ();
 *
 * This constructor constructs the root node with no child nodes and
 * value constructed with copy constructor
 *
 * @param T value - value to be copied and stored in this node
 *
 */
template<class T>
Node<T> :: Node (T value)
    :
    destroyed_ (false),
    left_      (nullptr),
    right_     (nullptr), 
    parent_    (nullptr),
    value_     (value)
{
}

template<class T>
Node<T> :: ~Node ()
{
    if ( ok () )
    {
        if ( parent_ )
        {
            if ( parent_->ok () )
            {
                if ( parent_->getLeftChild() == this )
                    parent_->attatchToLeft (nullptr);
                else
                    parent_->attatchToRight (nullptr);
            }
            if ( left_ )
                delete left_;
            if ( right_ )
                delete right_;
        }
    }
    left_   = nullptr;
    right_  = nullptr;
    parent_ = nullptr;

    destroyed_ = true;
}
